﻿#include "IOCPServer.h"
#include "IOContext.h"

#include <winnt.h>
#include <mstcpip.h> //tcp_keepalive

using namespace std;

CIOCPServer::CIOCPServer()
    : m_hShutdownEvent(nullptr), m_hIOCompletionPort(nullptr), m_phWorkerThreads(nullptr), m_nThreadNum(0),
    m_nListerPort(0), m_pListenSockContext(NULL), m_nAcceptPostCount(0), m_nConnectCount(0), m_nErrorCount(0)
{
    memset(m_szServerAddr, 0, sizeof(m_szServerAddr));
    memset(&m_csContextList, 0, sizeof(m_csContextList));
    m_stClientContextVect.clear();
    m_lpfnGetAcceptExSockAddrs = nullptr;
    m_lpfnAcceptEx = nullptr;
    m_lpLogFunc = nullptr;

    // 初始化网络库
    InitSocketLib();
}

CIOCPServer::~CIOCPServer()
{
    // 释放资源
    Release();
}

//************************************************************************
// 函数名称 : CIOCPServer::OnConnectionAcceptedEvent
// 函数描述 : 投递成功
// 输入参数 : const SSocketContext * pSocketContext
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::OnConnectionAcceptedEvent(const SSocketContext* pSocketContext)
{

}

//************************************************************************
// 函数名称 : CIOCPServer::OnCloseConnectEvent
// 函数描述 : 连接关闭
// 输入参数 : const SSocketContext * pSocketContext
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::OnCloseConnectEvent(const SSocketContext* pSocketContext)
{

}

//************************************************************************
// 函数名称 : CIOCPServer::OnConnectionErrorEvent
// 函数描述 : 连接错误
// 输入参数 : const SSocketContext * pSocketContext
// 输入参数 : int nErrID
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::OnConnectionErrorEvent(const SSocketContext* pSocketContext, int nErrID)
{

}

//************************************************************************
// 函数名称 : CIOCPServer::OnRecvCompletedEvent
// 函数描述 : 接收完成
// 输入参数 : const SSocketContext * pSocketContext
// 输入参数 : const SIOContext * pIoContext
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::OnRecvCompletedEvent(const SSocketContext* pSocketContext, const SIOContext* pIoContext)
{
    // 数据接收完成，原封不动发送出去
    SendData(pSocketContext, const_cast<SIOContext*>(pIoContext));
}

//************************************************************************
// 函数名称 : CIOCPServer::OnSendCompletedEvent
// 函数描述 : 发送完成
// 输入参数 : const SSocketContext * pSocketContext
// 输入参数 : const SIOContext * pIoContext
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::OnSendCompletedEvent(const SSocketContext* pSocketContext, const SIOContext* pIoContext)
{
    // 发送数据完成，继续接收数据
    RecvData(pSocketContext, const_cast<SIOContext*>(pIoContext));
}

//************************************************************************
// 函数名称 : CIOCPServer::InitSocketLib
// 函数描述 : 初始化Socket Lib
// 输出参数 :
// 返回类型 : int 
//************************************************************************
int CIOCPServer::InitSocketLib()
{
    //WSAStartup
    WSADATA stWsaData = {0};
    int nRet = WSAStartup(MAKEWORD(2, 2), &stWsaData);
    if (nRet != NO_ERROR)
    {
        TRACESVR("初始化WinSock 2.2 Failed!, nRet = %d", nRet);
        return nRet;
    }

    return 0;

}

//************************************************************************
// 函数名称 : CIOCPServer::CleanSocketLib
// 函数描述 : 清除Socket库
// 输出参数 :
// 返回类型 : void 
//************************************************************************
void CIOCPServer::CleanSocketLib()
{
    WSACleanup();
}

//************************************************************************
// 函数名称 : CreateEventA
// 函数描述 : 
// 输入参数 : _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes  NULL子进程不能继承
// 输入参数 : _In_ BOOL bManualReset    TRUE(函数将创建已康哥手动重置的事件对象，需要使用ResetEvent函数将事件状态设置为无信号状态)
//                                    FALSE(函数将创建一个自动重置的事件对象，并且在单个等待线程被释放后，系统将自动将事件状态重置为无信号状态)       
// 输入参数 : _In_ BOOL bInitialState   TRUE(事件对象的初始状态为有信号状态)
//                                    FALSE(无信号)
// 输入参数 : _In_opt_ LPCSTR lpName   事件对象的名称。名称限制为MAX_PATH字符。名称比较区分大小写
// 输出参数 :
// 返回类型 : HANDLE 
//************************************************************************
//HANDLE
//CreateEventA(
//    _In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,
//    _In_ BOOL bManualReset,
//    _In_ BOOL bInitialState,
//    _In_opt_ LPCSTR lpName
//);

//************************************************************************
// 函数名称 : CIOCPServer::GetNumOfProcessors
// 函数描述 : 获取处理器数量
// 输出参数 :
// 返回类型 : int 
//************************************************************************
int CIOCPServer::GetNumOfProcessors()
{
    SYSTEM_INFO stSystemInfo = {0};
    GetSystemInfo(&stSystemInfo);
    return stSystemInfo.dwNumberOfProcessors;
}

//************************************************************************
// 函数名称 : CIOCPServer::GetConnectCount
// 函数描述 : 获取当前连接数
// 输出参数 :
// 返回值   : int 
//************************************************************************
int CIOCPServer::GetConnectCount()
{
    return m_nConnectCount;
}

//************************************************************************
// 函数名称 : CIOCPServer::GetListerPort
// 函数描述 : 获取当前监听端口
// 输出参数 :
// 返回值   : unsigned int 
//************************************************************************
unsigned int CIOCPServer::GetListerPort()
{
    return m_nListerPort;
}

//************************************************************************
// 函数名称 : CIOCPServer::GetLocalIP
// 函数描述 : 获得本机的IP地址
// 输出参数 :
// 返回值   : string 
//************************************************************************
string CIOCPServer::GetLocalIP()
{
    char szHostName[MAX_PATH] = {0};                            
    gethostname(szHostName, sizeof(szHostName));
    /*struct */hostent FAR* lpHostEnt = gethostbyname(szHostName);
    if (nullptr == lpHostEnt)
    {
        return DEFAULT_SERVER_IP;
    }

    // 取得IP地址列表中的第一个为返回的IP(因为一台主机可能会绑定多个IP)
    const LPSTR lpAddr = lpHostEnt->h_addr_list[0];

    // 将IP转化为字符串形式
    in_addr inAddr;
    memmove(&inAddr, lpAddr, 4);

    return string(inet_ntoa(inAddr));
}


//************************************************************************
// 函数名称 : CIOCPServer::IsSocketAlive
// 函数描述 : 判断客户端Socket是否已经断开
// 输入参数 : SOCKET uiSocketID
// 输出参数 :
// 返回值   : bool 
// 备注：
//    判断客户端Socket是否已经断开，否则在一个无效的Socket上投递WSARecv操作会出现异常
//    使用的方法是尝试向这个socket发送数据，判断这个socket调用的返回值
//    因为如果客户端网络异常断开(例如客户端崩溃或者拔掉网线等)的时候，
//    服务器端是无法收到客户端断开的通知的
//************************************************************************
bool CIOCPServer::IsSocketAlive(SOCKET uiSocketID)
{
    if (uiSocketID == INVALID_SOCKET)
    {
        return false;
    }

    int nByteSend = send(uiSocketID, "", 0, 0);
    if (SOCKET_ERROR == nByteSend)
    {
        return false;
    }

    return true;
}

//************************************************************************
// 函数名称 : CIOCPServer::ShowMessage
// 函数描述 : 在主界面中显示信息
// 输入参数 : const char * pszFormat
// 输入参数 : ...
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::ShowMessage(const char* pszFormat, ...)
{
    if (NULL == pszFormat)
    {
        return;
    }

    char szBuff[512] = {0};
    va_list argList;
    va_start(argList, pszFormat);
    vsnprintf_s(szBuff, sizeof(szBuff), pszFormat, argList);
    va_end(argList);

    TRACESVR(szBuff);

    if (m_lpLogFunc)
    {
        m_lpLogFunc((string)szBuff);
    }

}

//************************************************************************
// 函数名称 : CIOCPServer::HandleError
// 函数描述 : 显示并处理IOCP上的错误
// 输入参数 : SSocketContext * pSocketContext
// 输入参数 : DWORD dwErrID
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::HandleError(SSocketContext* pSocketContext, DWORD dwErrID)
{
    if (nullptr == pSocketContext)
    {
        return true;
    }

    switch (dwErrID)
    {
    case WAIT_TIMEOUT:  // 超时
    {
        if (!IsSocketAlive(pSocketContext->m_uiSocket))
        {
            ShowMessage("Err 检测到客户端异常退出!!!");

            // 发送连接关闭事件
            OnCloseConnectEvent(pSocketContext);

            // 关闭连接
            CloseConnect(pSocketContext);

            break;
        }

        ShowMessage("Err 网络操作超时，正在尝试重新连接...");
        break;
    }
    case ERROR_NETNAME_DELETED:     // 客户端异常退出,也有可能是监听Socket挂掉
    {
        // 发送连接错误事件
        OnConnectionErrorEvent(pSocketContext, dwErrID);

        // 关闭连接
        if (!CloseConnect(pSocketContext))
        {
            ShowMessage("Err 关闭连接错误!!!");
        }

        break;
    }
    case ERROR_OPERATION_ABORTED:   // The I/O operation has been aborted because of either a thread exit or an application request.
    {
        ShowMessage("完成端口操作出错，线程退出。dwErrID = %u, dwCurrentThreadId = %u", dwErrID, GetCurrentThreadId());
        
        // 发送连接错误事件
        OnConnectionErrorEvent(pSocketContext, dwErrID);

        // 关闭连接
        if (!CloseConnect(pSocketContext))
        {
            ShowMessage("Err 关闭连接错误!!!");
        }

        return false;
    }
    default:
        ShowMessage("Err 其他异常！！！dwErrID = %u", dwErrID);
        break;
    }

    return true;
}

//************************************************************************
// 函数名称 : CIOCPServer::WorkerThreadProc
// 函数描述 : 工作线程回调函数
// 输入参数 : LPVOID lpParam
// 输出参数 :
// 返回类型 : DWORD WINAPI 
//************************************************************************
DWORD WINAPI CIOCPServer::WorkerThreadProc(LPVOID lpParam)
{
    if (nullptr == lpParam)
    {
        return -1;
    }

    SWorkerThreadParam* pThreadParam = (SWorkerThreadParam*)lpParam;
    CIOCPServer* pIOCPServer = pThreadParam->m_pIOCPServer;
    if (nullptr == pIOCPServer)
    {
        return -2;
    }

    pIOCPServer->ShowMessage("创建工作线程：m_dwThreadNo = %u, m_dwThreadID = %u", pThreadParam->m_dwThreadNo, pThreadParam->m_dwThreadID);

    // 循环处理请求，直到接收到Shutdown信息为止
    while (WAIT_OBJECT_0 != WaitForSingleObject(pIOCPServer->m_hShutdownEvent, 0))
    {
        DWORD dwNumberOfBytesTransferred = 0;
        SSocketContext* pSocketContext = nullptr;
        OVERLAPPED* pOverLapped = nullptr;
        BOOL bRes = GetQueuedCompletionStatus(pIOCPServer->m_hIOCompletionPort, &dwNumberOfBytesTransferred, (PULONG_PTR)pSocketContext, &pOverLapped, INFINITE);
        if (!bRes)
        {
            // 显示提示信息
            if (!pIOCPServer->HandleError(pSocketContext, GetLastError()))
            {
                break;
            }

            continue;
        }

        SIOContext* pIOContext = CONTAINING_RECORD(pOverLapped, SIOContext, m_stOverlapped);

        // 队列中返回的数据为空，退出信号
        if (nullptr == pSocketContext)
        {
            pIOCPServer->ShowMessage("收到退出信号!!! m_dwThreadNo = %u, m_dwThreadID = %u", pThreadParam->m_dwThreadNo, pThreadParam->m_dwThreadID);
            break;
        }

        // 判断是否有客户端断开连接
        if (dwNumberOfBytesTransferred == 0 && (pIOContext->m_nPostType == EMPostIOType::IO_TYPE_RECV || pIOContext->m_nPostType == EMPostIOType::IO_TYPE_SEND))
        {
            pIOCPServer->ShowMessage("客户端断开连接: [%s:%d]", inet_ntoa(pSocketContext->m_stClientAddr.sin_addr), ntohs(pSocketContext->m_stClientAddr.sin_port));
            pIOCPServer->OnCloseConnectEvent(pSocketContext);
            pIOCPServer->CloseConnect(pSocketContext);
            continue;
        }

        switch (pIOContext->m_nPostType)
        {
        case EMPostIOType::IO_TYPE_ACCEPT:
        {
            pIOContext->m_nTotalBytes = dwNumberOfBytesTransferred;
            pIOCPServer->DoAccept(pSocketContext, pIOContext);
            break;
        }
        case EMPostIOType::IO_TYPE_RECV:
        {
            pIOContext->m_nTotalBytes = dwNumberOfBytesTransferred;
            pIOCPServer->DoRecv(pSocketContext, pIOContext);
            break;
        }
        case EMPostIOType::IO_TYPE_SEND:
        {
            pIOContext->m_nSentBytes += dwNumberOfBytesTransferred;
            pIOCPServer->DoSend(pSocketContext, pIOContext);
            break;
        }
        default:
            pIOCPServer->ShowMessage("Err 类型错误!!! m_nPostType = %d", pIOContext->m_nPostType);
            break;
        }
    }

    pIOCPServer->ShowMessage("工作线程退出：m_dwThreadNo = %u, m_dwThreadID = %u", pThreadParam->m_dwThreadNo, pThreadParam->m_dwThreadID);
    
    return 0;
}

//************************************************************************
// 函数名称 : CIOCPServer::InitializeIOCP
// 函数描述 : 初始化IOCP
// 输出参数 :
// 返回类型 : int 
//************************************************************************
int CIOCPServer::InitializeIOCP()
{
    int nRet = 0;

    //If this parameter is zero, the system allows as many
    //concurrently running threads as there are processors in the system.
    //如果此参数为零，则系统允许的并发运行线程数量与系统中的处理器数量相同。
    m_hIOCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);
    if (nullptr == m_hIOCompletionPort)
    {
        ShowMessage("Err CreateIoCompletionPort Failed! nErrID = %d", GetLastError());
        return nRet;
    }

    m_nThreadNum = WORKER_THREADS_PER_PROCESSOR * GetNumOfProcessors();

    // 为工作者线程初始化句柄
    m_phWorkerThreads = new HANDLE[m_nThreadNum];

    // 创建工作线程
    DWORD dwThreadID = 0;
    for (int i = 0; i < m_nThreadNum; i++)
    {
        SWorkerThreadParam* pThreadParam = new SWorkerThreadParam;
        pThreadParam->m_pIOCPServer = this;
        pThreadParam->m_dwThreadNo = i + 1;
        dwThreadID = 0;

        // dwCreationFlags == 0 立即执行
        // dwCreationFlags == CREATE_SUSPENDED 创建后挂起，调用ResumeThread执行
        m_phWorkerThreads[i] = ::CreateThread(nullptr, 0, CIOCPServer::WorkerThreadProc, (LPVOID)pThreadParam, 0, &dwThreadID);
        if (nullptr == m_phWorkerThreads[i])
        {
            ShowMessage("Err CreateThread Failed! nErrID = %d, dwThreadNo = %d", GetLastError(), i + 1);
            continue;
        }
        pThreadParam->m_dwThreadID = dwThreadID;
    }

    ShowMessage("创建 %d 个工作线程!!!", m_nThreadNum);

    return 0;
}

//************************************************************************
// 函数名称 : CIOCPServer::Release
// 函数描述 : 释放资源
// 输出参数 :
// 返回类型 : void 
//************************************************************************
void CIOCPServer::Release()
{
    // 删除互斥量
    DeleteCriticalSection(&m_csContextList);

    // 关闭系统退出事件句柄
    RELEASE_HANDLE(m_hShutdownEvent);

    // 释放工作线程句柄
    for (int i = 0; i < m_nThreadNum; i++)
    {
        RELEASE_HANDLE(m_phWorkerThreads[i]);
    }

    // 释放工作线程指针
    RELEASE_ARRAY(m_phWorkerThreads);

    // 释放IOCP句柄
    RELEASE_HANDLE(m_hIOCompletionPort);

    // 关闭监听Sock资源
    RELEASE_POINTER(m_pListenSockContext);

    // 清除网络库
    CleanSocketLib();

    ShowMessage("资源释放完毕!!!!");
}

//************************************************************************
// 函数名称 : CIOCPServer::PostAccept
// 函数描述 : 投递完成端口请求
// 输入参数 : SIOContext * pIOContext
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::PostAccept(SIOContext* pIOContext)
{
    if (NULL == pIOContext || INVALID_SOCKET == m_pListenSockContext->m_uiSocket)
    {
        ShowMessage("Err is NULL or m_pListenSockContext->m_uiSocket = %d", m_pListenSockContext->m_uiSocket);
        return false;
    }

    pIOContext->ResetBuffer();
    pIOContext->m_nPostType = EMPostIOType::IO_TYPE_ACCEPT;

    // SOCKET hClient = accept(hSocket, NULL, NULL); //传统accept
    // 为以后新连入的客户端先准备好Socket( 这个是与传统accept最大的区别 )
    pIOContext->m_uiAcceptSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
    if (INVALID_SOCKET == pIOContext->m_uiAcceptSocket)
    {
        ShowMessage("Err 创建用于AcceptEx的Socket失败!!! nErr = %d", WSAGetLastError());
        return false;
    }

    // 投递AcceptEx 
    DWORD dwAddressLength = sizeof(SOCKADDR_IN) + 16;   // 参考MSDN
    DWORD dwBytesReceived = 0;                          // 将接收缓冲置为0,令AcceptEx直接返回,防止拒绝服务攻击
    WSABUF* pWSABuff = &(pIOContext->m_stWsaBuf);
    bool bRes = m_lpfnAcceptEx(m_pListenSockContext->m_uiSocket, pIOContext->m_uiAcceptSocket, pIOContext->m_stWsaBuf.buf, 0, dwAddressLength, dwAddressLength, &dwBytesReceived, &(pIOContext->m_stOverlapped));
    if (!bRes && WSAGetLastError() != WSA_IO_PENDING)
    {
        ShowMessage("Err 投递 AcceptEx 失败!!! nErr = %d, m_uiSocket = %u, m_uiAcceptSocket = %u", WSAGetLastError(), m_pListenSockContext->m_uiSocket, pIOContext->m_uiAcceptSocket);
        return false;
    }

    // 增加投递 AcceptEx个数
    InterlockedIncrement(&m_nAcceptPostCount);

    return true;
}

//************************************************************************
// 函数名称 : CIOCPServer::InitializeListenSocket
// 函数描述 : 初始化ListenSocket
// 输出参数 :
// 返回类型 : int 
//************************************************************************
int CIOCPServer::InitializeListenSocket()
{
    int nRet = 0;

    // 生成用于监听的Socket的信息
    m_pListenSockContext = new SSocketContext();

    // 需要使用重叠IO，必须得使用WSASocket来建立Socket，才可以支持重叠IO操作(WSA_FLAG_OVERLAPPED)
    m_pListenSockContext->m_uiSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
    if (m_pListenSockContext->m_uiSocket == INVALID_SOCKET)
    {
        ShowMessage("Err WSASocket Failed! nRet = %d", WSAGetLastError());
        return -1;
    }

    // 填充服务器地址信息，用于绑定Socket
    sockaddr_in stServerAddr;
    ZeroMemory(&stServerAddr, sizeof(stServerAddr));
    stServerAddr.sin_family = AF_INET;
    stServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    stServerAddr.sin_port = htons(m_nListerPort);

    nRet = bind(m_pListenSockContext->m_uiSocket, (sockaddr*)&stServerAddr, sizeof(stServerAddr));
    if (SOCKET_ERROR == nRet)
    {
        ShowMessage("Err bind Failed! nRet = %d", WSAGetLastError());
        return -2;
    }

    nRet = listen(m_pListenSockContext->m_uiSocket, MAX_LISTER_SOCKET);
    if (SOCKET_ERROR == nRet)
    {
        ShowMessage("Err listen Failed! nRet = %d", WSAGetLastError());
        return -3;
    }

    // 将Listen Socket 绑定至完成端口中
    HANDLE pIOCPHandle = CreateIoCompletionPort((HANDLE)(m_pListenSockContext->m_uiSocket), m_hIOCompletionPort, (DWORD)m_pListenSockContext, 0);
    if (nullptr == pIOCPHandle)
    {
        ShowMessage("Err CreateIoCompletionPort Failed! nRet = %d", WSAGetLastError());
        return -4;
    }

    // 使用AcceptEx函数，因为这个是属于WinSock2规范之外的微软另外提供的扩展函数
    // 所以需要额外获取一下函数的指针，获取AcceptEx函数指针
    DWORD dwBytes = 0;
    GUID GuidAcceptEx = WSAID_ACCEPTEX;
    nRet = WSAIoctl(m_pListenSockContext->m_uiSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &m_lpfnAcceptEx, sizeof(m_lpfnAcceptEx), &dwBytes, NULL, NULL);
    if (nRet == SOCKET_ERROR)
    {
        ShowMessage("Err WSAIoctl 未能获取AcceptEx函数指针。错误代码: %d", WSAGetLastError());
        return -5;
    }

    GUID GuidGetAcceptExSockAddrs = WSAID_GETACCEPTEXSOCKADDRS;
    nRet = WSAIoctl(m_pListenSockContext->m_uiSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidGetAcceptExSockAddrs, sizeof(GuidGetAcceptExSockAddrs), &m_lpfnGetAcceptExSockAddrs, sizeof(m_lpfnGetAcceptExSockAddrs), &dwBytes, NULL, NULL);
    if (nRet == SOCKET_ERROR)
    {
        ShowMessage("Err WSAIoctl 未能获取GuidGetAcceptExSockAddrs函数指针。错误代码: %d", WSAGetLastError());
        return -6;
    }

    // 为AcceptEx 准备参数，然后投递AcceptEx I/O请求
    // 创建10个套接字，投递AcceptEx请求，即共有10个套接字进行accept操作；
    for (size_t i = 0; i < MAX_POST_ACCEPT; i++)
    {
        // 新建一个IO_CONTEXT
        SIOContext* pIoContext = m_pListenSockContext->GetNewIOContext();
        if (NULL != pIoContext && !PostAccept(pIoContext))
        {
            m_pListenSockContext->RemoveIOContext(pIoContext);
            return 0;
        }
    }

    ShowMessage("投递【%d/%d】个AcceptEx请求完毕!!!", m_nAcceptPostCount, MAX_POST_ACCEPT);

    return 0;
}

//************************************************************************
// 函数名称 : CIOCPServer::OnStartServer
// 函数描述 : 启动服务
// 输入参数 : int nPort
// 输出参数 :
// 返回类型 : int 
//************************************************************************
int CIOCPServer::OnStartServer(int nPort /*= DEFAULE_SERVER_PORT*/)
{
    m_nListerPort = nPort;

    // 初始化线程互斥量
    InitializeCriticalSection(&m_csContextList);

    // 系统退出事件
    int nRet = 0;
    m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (NULL == m_hShutdownEvent)
    {
        ShowMessage("Err CreateEvent Failed! nRet = %d", GetLastError());
        return -1;
    }

    // 初始化IOCP
    nRet = InitializeIOCP();
    if (nRet != 0)
    {
        // 释放资源
        Release();
        ShowMessage("Err InitializeIOCP Failed! nRet = %d", nRet);
        return -2;
    }

    // 初始化ListenSocket
    nRet = InitializeListenSocket();
    if (nRet != 0)
    {
        // 释放资源
        Release();
        ShowMessage("Err InitializeListenSocket Failed! nRet = %d", nRet);
        return -3;
    }

    ShowMessage("系统准备就绪，等待连接...");

    return 0;

}

//************************************************************************
// 函数名称 : CIOCPServer::OnStopServer
// 函数描述 : 停止服务
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::OnStopServer()
{
    if (nullptr != m_pListenSockContext && m_pListenSockContext->m_uiSocket != INVALID_SOCKET)
    {
        // 激活关闭消息通知
        SetEvent(m_hShutdownEvent);

        // 通知所有IOCP操作退出
        for (int i = 0; i < m_nThreadNum; i++)
        {
            PostQueuedCompletionStatus(m_hIOCompletionPort, 0, NULL, NULL);
        }

        // 等待所有客户端资源退出
        WaitForMultipleObjects(m_nThreadNum, m_phWorkerThreads, TRUE, INFINITE);

        // 清除客户端列表信息
        ClearContextList();

        // 释放其他资源
        Release();

        ShowMessage("停止监听...");
    }
}

//************************************************************************
// 函数名称 : CIOCPServer::RemoveSocketContext
// 函数描述 : 移除连接数据
// 输入参数 : SSocketContext * pSocketContext
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::RemoveSocketContext(SSocketContext* pSocketContext)
{
    EnterCriticalSection(&m_csContextList);
    for (vector<SSocketContext*>::iterator it = m_stClientContextVect.begin(); it != m_stClientContextVect.end(); it++)
    {
        SSocketContext* pContext = *it;
        if (pContext == pSocketContext)
        {
            delete pContext;
            pContext = nullptr;
            it = m_stClientContextVect.erase(it);
            break;
        }
    }

    LeaveCriticalSection(&m_csContextList);
}

//************************************************************************
// 函数名称 : CIOCPServer::AddSocketContext
// 函数描述 : 将客户端的相关信息存储到数组中
// 输入参数 : SSocketContext * pSocketContext
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::AddSocketContext(SSocketContext* pSocketContext)
{
    EnterCriticalSection(&m_csContextList);
    m_stClientContextVect.push_back(pSocketContext);
    LeaveCriticalSection(&m_csContextList);
}


//************************************************************************
// 函数名称 : CIOCPServer::ClearContextList
// 函数描述 : 清除客户端信息
// 输出参数 :
// 返回值   : void 
//************************************************************************
void CIOCPServer::ClearContextList()
{
    EnterCriticalSection(&m_csContextList);

    for (int i = 0; i < (int)m_stClientContextVect.size(); i++)
    {
        delete m_stClientContextVect.at(i);
    }
    m_stClientContextVect.clear();

    LeaveCriticalSection(&m_csContextList);
}

//************************************************************************
// 函数名称 : CIOCPServer::CloseConnect
// 函数描述 : 关闭连接
// 输入参数 : SSocketContext * pSocketContext
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::CloseConnect(SSocketContext* pSocketContext)
{
    if (nullptr == pSocketContext)
    {
        return false;
    }

    if (pSocketContext != m_pListenSockContext)
    {
        InterlockedIncrement(&m_nErrorCount);
        return false;
    }

    // 减少连接数
    InterlockedIncrement(&m_nConnectCount);

    // 移除连接数据
    RemoveSocketContext(pSocketContext);

    return true;
}

//************************************************************************
// 函数名称 : CIOCPServer::SendData
// 函数描述 : 发送数据
// 输入参数 : const SSocketContext * pSocketContext
// 输入参数 : const SIOContext * pIoContext
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::SendData(const SSocketContext* pSocketContext, SIOContext* pIoContext)
{
    if (nullptr == pSocketContext || nullptr == pIoContext)
    {
        return false;
    }

    pIoContext->m_nPostType = EMPostIOType::IO_TYPE_SEND;
    pIoContext->m_nTotalBytes = 0;
    pIoContext->m_nSentBytes = 0;

    DWORD dwNumberOfBytesSent = 0;
    DWORD dwFlag = 0;
    int nRet = WSASend(pSocketContext->m_uiSocket, &pIoContext->m_stWsaBuf, 1, &dwNumberOfBytesSent, dwFlag, &pIoContext->m_stOverlapped, NULL);
    if (nRet == SOCKET_ERROR && WSA_IO_PENDING != WSAGetLastError())
    {
        ShowMessage("Err 投递WSASend失败!!! nErrID = %d", WSAGetLastError());
        CloseConnect(const_cast<SSocketContext*>(pSocketContext));
        return false;
    }

    return true;
}

//************************************************************************
// 函数名称 : CIOCPServer::SendData
// 函数描述 : 向指定客户端发送数据
// 输入参数 : SSocketContext * pSocketContext
// 输入参数 : const char * pData
// 输入参数 : int nLen
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::SendData(SSocketContext* pSocketContext, const char* pData, int nLen)
{
    if (nullptr == pSocketContext || nullptr == pData || nLen <= 0)
    {
        return false;
    }

    SIOContext* pIOContext = pSocketContext->GetNewIOContext();
    pIOContext->m_uiAcceptSocket = pSocketContext->m_uiSocket;
    pIOContext->m_nPostType = EMPostIOType::IO_TYPE_SEND;
    pIOContext->m_nTotalBytes = nLen;
    pIOContext->m_stWsaBuf.len = nLen;
    memcpy_s(pIOContext->m_stWsaBuf.buf, pIOContext->m_stWsaBuf.len, pData, nLen);

    return SendData(pSocketContext, pIOContext);

}

//************************************************************************
// 函数名称 : CIOCPServer::RecvData
// 函数描述 : 继续接收指定客户端的数据
// 输入参数 : const SSocketContext * pSocketContext
// 输入参数 : SIOContext * pIoContext
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::RecvData(const SSocketContext* pSocketContext, SIOContext* pIoContext)
{
    if (nullptr == pSocketContext || nullptr == pIoContext)
    {
        return false;
    }

    pIoContext->ResetBuffer();
    pIoContext->m_nPostType = EMPostIOType::IO_TYPE_RECV;
    pIoContext->m_nTotalBytes = 0;
    pIoContext->m_nSentBytes = 0;

    DWORD dwNumberOfBytesRecvd = 0;
    DWORD dwFlags = 0;
    int nRet = WSARecv(pIoContext->m_uiAcceptSocket, &pIoContext->m_stWsaBuf, 1, &dwNumberOfBytesRecvd, &dwFlags, &pIoContext->m_stOverlapped, NULL);
    if (nRet == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
    {
        ShowMessage("Err 投递WSARecv失败！！！nErrID = %d", WSAGetLastError());
        CloseConnect(const_cast<SSocketContext*>(pSocketContext));
        return false;
    }

    return true;
}

//************************************************************************
// 函数名称 : CIOCPServer::DoAccept
// 函数描述 : 新的客户端接入
// 输入参数 : SSocketContext * pSocketContext   这里的pSoContext是listenSocketContext
// 输入参数 : SIOContext * pIOContext           本次accept操作对应的数据结构
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::DoAccept(SSocketContext* pSocketContext, SIOContext* pIOContext)
{
    if (nullptr == pSocketContext || nullptr == pIOContext)
    {
        return false;
    }

    // 1.获取新连接的客户端地址
    SOCKADDR_IN* pClientAddr = NULL;
    SOCKADDR_IN* pLocalAddr = NULL;
    DWORD dwAddrLen = sizeof(SOCKADDR_IN) + 16; // MSDN
    int nLocalSockaddrLength = 0;
    int nRemoteSockaddrLength = 0;
    m_lpfnGetAcceptExSockAddrs(pIOContext->m_stWsaBuf.buf, 0, dwAddrLen, dwAddrLen, (LPSOCKADDR*)&pLocalAddr, &nLocalSockaddrLength, (LPSOCKADDR*)&pClientAddr, &nRemoteSockaddrLength);

    // 2.为新连接建立一个SSocketContext
    SSocketContext* pNewSocketContext = new SSocketContext;
    pNewSocketContext->m_uiSocket = pIOContext->m_uiAcceptSocket;
    //memcpy_s(&(pNewSocketContext->m_stClientAddr), sizeof(SOCKADDR_IN), pClientAddr, sizeof(SOCKADDR_IN));
    memcpy(&(pNewSocketContext->m_stClientAddr), pClientAddr, sizeof(SOCKADDR_IN));
    AddSocketContext(pNewSocketContext);

    // 3.将listenSocketContext的IOContext 重置后继续投递AcceptEx
    if (!PostAccept(pIOContext))
    {
        pSocketContext->RemoveIOContext(pIOContext);
    }

    // 4. 将新socket和完成端口绑定
    HANDLE hTemp = CreateIoCompletionPort((HANDLE)pNewSocketContext->m_uiSocket, m_hIOCompletionPort, (DWORD)pNewSocketContext, 0);
    if (nullptr == hTemp)
    {
        ShowMessage("Err 绑定IOCP失败！！！m_uiSocket = %d, nErrID = %d", pNewSocketContext->m_uiSocket, GetLastError());
        OnCloseConnectEvent(pNewSocketContext);
        CloseConnect(pNewSocketContext);
        return false;
    }

    // 5.设置心跳包
    //struct tcp_keepalive {
    //    ULONG onoff;
    //    ULONG keepalivetime;
    //    ULONG keepaliveinterval;
    //};
    tcp_keepalive stAliveIn, stAliveOut;
    memset(&stAliveIn, 0, sizeof(stAliveIn));
    memset(&stAliveOut, 0, sizeof(stAliveOut));
    stAliveIn.keepalivetime = KEEP_ALIVE_TIME;
    stAliveIn.keepaliveinterval = KEEP_ALIVE_INTERVAL;
    stAliveIn.onoff = 1;
    DWORD dwBytesReturned = 0;
    int nRet = WSAIoctl(pNewSocketContext->m_uiSocket, SIO_KEEPALIVE_VALS, &stAliveIn, sizeof(stAliveIn), &stAliveOut, sizeof(stAliveOut), &dwBytesReturned, NULL, NULL);
    if (nRet == SOCKET_ERROR)
    {
        ShowMessage("Err 设置心跳包错误！！！ nErrID = %d", WSAGetLastError());
    }

    // 6.建立recv操作所需的ioContext，在新连接的socket上投递recv请求
    SIOContext* pNewIOContext = pNewSocketContext->GetNewIOContext();
    if (nullptr == pNewIOContext)
    {
        ShowMessage("Err GetNewIOContext Failed!");
        OnCloseConnectEvent(pNewSocketContext);
        CloseConnect(pNewSocketContext);
        return false;
    }

    pNewIOContext->m_nPostType = EMPostIOType::IO_TYPE_RECV;
    pNewIOContext->m_uiAcceptSocket = pNewSocketContext->m_uiSocket;
    RecvData(pNewSocketContext, pNewIOContext);

    // 连接成功
    OnConnectionAcceptedEvent(pNewSocketContext);

    // 增加连接数
    InterlockedIncrement(&m_nConnectCount);
    InterlockedIncrement(&m_nAcceptPostCount);

    return true;
}


//************************************************************************
// 函数名称 : CIOCPServer::DoRecv
// 函数描述 : 在有接收的数据到达的时候，进行处理
// 输入参数 : SSocketContext * pSocketContext
// 输入参数 : SIOContext * pIoContext
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::DoRecv(SSocketContext* pSocketContext, SIOContext* pIoContext)
{
    if (nullptr == pSocketContext || nullptr == pIoContext)
    {
        return false;
    }

    // 通知应该层数据接收完毕
    OnRecvCompletedEvent(pSocketContext, pIoContext);
    
    return true;
}

//************************************************************************
// 函数名称 : CIOCPServer::DoSend
// 函数描述 : 发送数据
// 输入参数 : SSocketContext * pSocketContext
// 输入参数 : SIOContext * pIoContext
// 输出参数 :
// 返回值   : bool 
//************************************************************************
bool CIOCPServer::DoSend(SSocketContext* pSocketContext, SIOContext* pIoContext)
{
    if (nullptr == pSocketContext || nullptr == pIoContext)
    {
        return false;
    }

    // 数据还没有发送完成，继续发送
    if (pIoContext->m_nTotalBytes > pIoContext->m_nSentBytes)
    {
        pIoContext->m_stWsaBuf.buf = pIoContext->m_szBuffer + pIoContext->m_nSentBytes;
        pIoContext->m_stWsaBuf.len = pIoContext->m_nTotalBytes - pIoContext->m_nSentBytes;
        return SendData(pSocketContext, pIoContext);
    }

    // 通知应用层，数据发送完毕
    OnSendCompletedEvent(pSocketContext, pIoContext);

    return true;
}

